package controllers;

import com.google.gson.ExclusionStrategy;
import com.google.gson.FieldAttributes;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import models.Barang;
import models.Kategori;
import models.Pesanan;
import models.PesananItem;
import models.Profil;
import models.User;
import system.Controller;
import system.WebService;

/**
 * Service Controller
 * 
 * @author Rezan Achmad
 */
@WebServlet(name = "ServiceController", urlPatterns = {"/service", "/service/"})
public class ServiceController extends Controller {

    @Override
    protected void initRules() {
    }
    
    GsonBuilder gsonBuilder = new GsonBuilder();
    Gson gson = gsonBuilder.setExclusionStrategies(new ExclusionStrategy() {

        @Override
        public boolean shouldSkipField(FieldAttributes f) {
            return f.getName().equals("errors") || f.getName().equals("attributesLabel") || f.getName().equals("request");
        }

        @Override
        public boolean shouldSkipClass(Class<?> clazz) {
            return false;
        }
    }).create();

    @Override
    protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String operation = request.getParameter("operation");
        String output = "";

        if (operation.equals("barang.get")) {
            output = barangGet(request);
        } else if (operation.equals("barang.getAll")) {
            output = barangGetAll(request);
        } else if (operation.equals("kategori.get")) {
            output = kategoryGet(request);
        } else if (operation.equals("kategori.getAll")) {
            output = kategoryGetAll(request);
        } else if (operation.equals("user.getInfo")) {
            output = userGetInfo(request);
        } else if (operation.equals("pesanan.add")) {
            output = pesananAdd(request, response);
        } else if (operation.equals("pesanan.confirmPay")) {
            output = pesananConfirm(request, response);
        } else if (operation.equals("pesanan.getAll")) {
            output = pesananGetAll(request);
        } else if (operation.equals("profil.get")) {
            output = profilGet(request);
        } else if (operation.equals("login")) {
            output = login(request);
        } else if (operation.equals("getShippingServices")) {
            output = getShippingServices(request);
        }

        // Send Response
        response.setContentType("text;charset=UTF-8");
        PrintWriter out = response.getWriter();
        out.write(output);
        out.close();
    }

    /**
     * Kelola service untuk mengambil satu barang. Parameter yang tersedia yaitu <code>barang_id</code>.
     * 
     * @param request HTTP Request
     * @return Mengembalikan string JSON barang jika ditemukan atau string kosong jika tidak ditemukan.
     */
    private String barangGet(HttpServletRequest request) {
        String id = request.getParameter("barang_id");
        Barang barang = Barang.get(Integer.parseInt(id));
        return gson.toJson(barang);
    }

    /**
     * Kelola service untuk mengambil banyak barang. Paramater yang tesedia yaitu
     * <code>term</code> yang merupakan pattern nama barang serta <code>kategori_id</code>
     * yang merupakan id kategori barang.
     * 
     * @param request HTTP Request
     * @return Mengembalikan string JSON array barang jika ditemukan atau string kosong jika tidak ditemukan.
     */
    private String barangGetAll(HttpServletRequest request) {
        String sql = "SELECT * FROM `barang`";
        StringBuilder condition = new StringBuilder("'1'='1'");
        String term = "";
        String kategori_id = "";

        if ((term = request.getParameter("term")) != null) {
            condition.append(" AND `nama` LIKE '%").append(term).append("%'");
        }

        if ((kategori_id = request.getParameter("kategori_id")) != null) {
            condition.append(" AND `kategori_id`='").append(kategori_id).append("'");
        }

        if (!condition.toString().equals("")) {
            sql += " WHERE " + condition;
        }

        return gson.toJson(Barang.getAllBySql(sql));
    }

    /**
     * Kelola service untuk mengambil satu kategori. Parameter yang tersedia yaitu
     * <code>kategori_id</code>.
     * 
     * @param request HTTP Request
     * @return Mengembalikan string JSON kategori jika ditemukan atau string kosong jika tidak ditemukan.
     */
    private String kategoryGet(HttpServletRequest request) {
        String id = request.getParameter("kategori_id");
        Kategori kategori;

        try {
            kategori = Kategori.get(Integer.parseInt(id));
        } catch (NumberFormatException ex) {
            return "";
        }

        return gson.toJson(kategori);
    }

    /**
     * Kelola service untuk mengambil seluruh kategori.
     * 
     * @param request HTTP Request
     * @return Mengembalikan string JSON array kategori jika ditemukan atau string kosong jika tidak ditemukan.
     */
    private String kategoryGetAll(HttpServletRequest request) {
        return gson.toJson(Kategori.getAll());
    }

    /**
     * Kelola service untuk mendapat informasi user tertentu. Parameter yang 
     * tersedia yaitu <code>username</code>.
     * 
     * @param request HTTP Request
     * @return Mengembalikan string JSON informasi user jika ditemukan atau string kosong jika tidak ditemukan.
     */
    private String userGetInfo(HttpServletRequest request) {
        User user = User.getByEmail(request.getParameter("username"));

        gson = gsonBuilder.setExclusionStrategies(new ExclusionStrategy() {

            @Override
            public boolean shouldSkipField(FieldAttributes f) {
                return f.getName().equals("password") || f.getName().equals("is_registered");
            }

            @Override
            public boolean shouldSkipClass(Class<?> clazz) {
                return false;
            }
        }).create();

        return gson.toJson(user);
    }

    /**
     * Kelola service untuk memesan barang. GET Parameter yang tersedia yaitu 
     * <code>username</code> dan <code>password</code> yang digunakan untuk 
     * autentikasi. POST Parameter yang tersedia yaitu <code>data</code> yaitu 
     * data barang-barang yang akan dipesan, contoh datan :
     * <code>[{barang_id:3, jumlah:10}, {barang_id:2, jumlah:10}]</code>
     * 
     * @param request HTTP Request.
     * @param response HTTP Response.
     * @return Mengembalikan id pesanan jika pemesanan berhasil atau string kosong jika gagal.
     */
    private String pesananAdd(HttpServletRequest request, HttpServletResponse response) {
        // Authenticate User
        if (!authenticateUser(request)) {
            return "autentikasi gagal";
        }

        // Get user instance
        User user = User.getByEmail(request.getParameter("username"));

        // Init Pesanan
        String kirim = request.getParameter("kirim");
        Pesanan pesanan = new Pesanan();
        pesanan.status = 1;
        pesanan.user_id = user.id;
        
        if(kirim != null && "1".equals(kirim)) {
            pesanan.kirim = 1;
            pesanan.alamat_kirim = request.getParameter("alamat_kirim");
            try {
                pesanan.shipping_service_id = Integer.parseInt(request.getParameter("shipping_service_id")); 
                System.out.println("shipping service id " + pesanan.shipping_service_id);
            } catch(Exception e){
                pesanan.shipping_service_id = 0;
            }
        }
        
        // Check tukar point
        String usePoin = request.getParameter("use_point");
        if (usePoin != null && !usePoin.isEmpty() && "1".equals(usePoin)) {
            if (!User.tukarPoin(user.email)) {
                return "Tidak bisa memakai poin. Poin Anda tidak mencukupi.";
            } else {
                pesanan.diskon = 10;
            }
        }

        try {
            // Init PesananItem
            String data = request.getParameter("data");
            PesananItem items[] = gson.fromJson(data, PesananItem[].class);

            if (items == null) {
                throw new Exception("data tidak boleh kosong");
            }

            // Add Pesanan and its item
            if (pesanan.add(items)) {
                return Integer.toString(pesanan.id);
            } else {
                throw new Exception(pesanan.getErrorGlobal());
            }
        } catch (Exception e) {
            if(pesanan.diskon > 0) {
                User.batalTukarPoin(user.email);
            }
            
            return e.getMessage();
        }
    }

    /**
     * Kelola service untuk konfirmasi pembayaran. GET Parameter yang tersedia yaitu 
     * <code>username</code> dan <code>password</code> yang digunakan untuk 
     * autentikasi serta <code>pesanan_id</code>.
     * 
     * @param request HTTP Request.
     * @param response HTTP Response.
     * @return Mengembalikan string <code>success</code> jika berhasil atau string kosong jika gagal.
     */
    private String pesananConfirm(HttpServletRequest request, HttpServletResponse response) {
        // Authenticate User
        if (!authenticateUser(request)) {
            return "autentikasi gagal";
        }

        // Get pesanan_id
        int pesananId;
        try {
            pesananId = Integer.parseInt(request.getParameter("pesanan_id"));
        } catch (NumberFormatException ex) {
            // Parameter not found
            return "";
        }

        // Get object Pesanan
        Pesanan pesanan = Pesanan.getInstance().get(pesananId);

        // Confirm and return result
        if (pesanan == null) {
            return "pesanan tidak ditemukan";
        } else {
            return (pesanan.confirmPay()) ? "success" : "konfirmasi gagal";
        }
    }

    /**
     * Kelola service untuk mengambil seluruh histori pesanan user tertentu. GET 
     * Parameter yang tersedia yaitu <code>username</code> dan 
     * <code>password</code> yang digunakan untuk autentikasi serta 
     * <code>status</code> untuk filter dengan status tertentu.
     * 
     * @param request HTTP Request
     * @return Mengembalikan string JSON array pesanan jika ditemukan atau string kosong jika tidak ditemukan.
     */
    private String pesananGetAll(HttpServletRequest request) {
        // Authenticate User
        if (!authenticateUser(request)) {
            return "";
        }

        // Get user
        User user = User.getByEmail(request.getParameter("username"));

        // Get status if any
        int status = 0;
        try {
            status = Integer.parseInt(request.getParameter("status"));
        } catch (NumberFormatException ex) {
            status = 0;
        }

        // Get all Pesanan
        ArrayList<Pesanan> pesanans = null;
        if (status > 0) {
            pesanans = Pesanan.getInstance().getAllWithItems(user.id, status);
        } else {
            pesanans = Pesanan.getInstance().getAllWithItems(user.id);
        }

        return gson.toJson(pesanans);
    }

    /**
     * Mengambil profil toko tempe.
     * @param request HTTP Request
     * @return Mengembalikan string JSON informasi tempe jika ditemukan atau string kosong jika tidak ditemukan.
     */
    private String profilGet(HttpServletRequest request) {
        return gson.toJson(Profil.getCurrentProfil());
    }

    /**
     * Login ke system. GET Parameter yang tersedia yaitu <code>username</code> 
     * dan <code>password</code>.
     * @param request HTTP Request.
     * @return Mengembalikan string <code>success</code> jika berhasil atau string kosong jika gagal.
     */
    private String login(HttpServletRequest request) {
        return (authenticateUser(request)) ? "success" : "";
    }

    /**
     * Autentikasi user. Username dan password berasal dari GET parameter 
     * <code>username</code> dan <code>password</code>.
     * 
     * @param request HTTP Request.
     * @return Mengembalikan true jika autentikasi berhasil atau false jika gagal.
     */
    private boolean authenticateUser(HttpServletRequest request) {
        // Init Data
        User user = new User();
        user.email = request.getParameter("username");
        user.password = request.getParameter("password");

        // Log
        System.out.println("email : " + user.email);
        System.out.println("password : " + user.password);
        
        // Validate data
        if (user.password == null || user.email == null) {
            return false;
        }

        // Authenticae
        return user.authenticate();
    }

    private String getShippingServices(HttpServletRequest request) {
        return gson.toJson(WebService.getShippingServices());
    }
}
